/*
 *    UNIVERSIDADE DE SÃO PAULO.
 *    Author: Marco Aurélio Gerosa (gerosa@ime.usp.br)
 *    This project was/is sponsored by RNP and FAPESP.
 *
 *    This file is part of Groupware Workbench (http://www.groupwareworkbench.org.br).
 *
 *    Groupware Workbench is free software: you can redistribute it and/or modify
 *    it under the terms of the GNU Lesser General Public License as published by
 *    the Free Software Foundation, either version 3 of the License, or
 *    (at your option) any later version.
 *
 *    Groupware Workbench is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *    GNU Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public License
 *    along with Swift.  If not, see <http://www.gnu.org/licenses/>.
 */
package br.org.groupwareworkbench.eureka.hardware;

import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.Transient;

import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;

import br.org.groupwareworkbench.collablet.coord.user.User;
import br.org.groupwareworkbench.core.bd.ObjectDAO;
import br.org.groupwareworkbench.core.framework.Collablet;

@Entity
public class Hardware {
    private static final ObjectDAO<Hardware, String> DAO = new ObjectDAO<Hardware, String>(Hardware.class);

    public static final String STRING_SEPARATOR = "###";

    @Id
    private String gatiCode;
    @ElementCollection
    private Map<Date, User> listMaintenances;

    @ManyToOne
    private Collablet collablet;

    @Transient
    private String lastUpdate;
    @Transient
    private String lastAccess;
    @Transient
    private String name;
    @Transient
    private String function;
    @Transient
    private String localization;
    @Transient
    private String localizationComplement;
    @Transient
    private String serialNumber;
    @Transient
    private String status;
    @Transient
    private String costCenter;
    @Transient
    private String observations;
    @Transient
    private List<String> hardwareData = new ArrayList<String>();
    /*
     * @Transient private List<String> diskData = new ArrayList<String>();
     */
    @Transient
    private List<String> softwareData = new ArrayList<String>();

    public Hardware() {
        listMaintenances = new HashMap<Date, User>();
    }

    public String getGatiCode() {
        return gatiCode;
    }

    public void setGatiCode(String gatiCode) {
        this.gatiCode = gatiCode;
    }

    public Collablet getCollablet() {
        return collablet;
    }

    public void setCollablet(Collablet collablet) {
        this.collablet = collablet;
    }

    public Map<Date, User> getListMaintenances() {
        return listMaintenances;
    }

    public void setListMaintenances(Map<Date, User> listMaintenances) {
        this.listMaintenances = listMaintenances;
    }

    public String getLastUpdate() {
        return lastUpdate;
    }

    public void setLastUpdate(String lastUpdate) {
        this.lastUpdate = lastUpdate;
    }

    public String getLastAccess() {
        return lastAccess;
    }

    public void setLastAccess(String lastAccess) {
        this.lastAccess = lastAccess;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getFunction() {
        return function;
    }

    public void setFunction(String function) {
        this.function = function;
    }

    public String getLocalization() {
        return localization;
    }

    public void setLocalization(String localization) {
        this.localization = localization;
    }

    public String getLocalizationComplement() {
        return localizationComplement;
    }

    public void setLocalizationComplement(String localizationComplement) {
        this.localizationComplement = localizationComplement;
    }

    public String getSerialNumber() {
        return serialNumber;
    }

    public void setSerialNumber(String serialNumber) {
        this.serialNumber = serialNumber;
    }

    public String getStatus() {
        return status;
    }

    public void setStatus(String status) {
        this.status = status;
    }

    public String getCostCenter() {
        return costCenter;
    }

    public void setCostCenter(String costCenter) {
        this.costCenter = costCenter;
    }

    public String getObservations() {
        return observations;
    }

    public void setObservations(String observations) {
        this.observations = observations;
    }

    public List<String> getHardwareData() {
        return hardwareData;
    }

    public void setHardwareData(List<String> hardwareData) {
        this.hardwareData = hardwareData;
    }

    public List<String> getSoftwareData() {
        return softwareData;
    }

    public void setSoftwareData(List<String> softwareData) {
        this.softwareData = softwareData;
    }

    public Map<Date, User> getMaintenances() {
        return listMaintenances;
    }

    public void addMaintenance(User maintainer) {
        this.listMaintenances.put(new Date(), maintainer);
    }

    public boolean readDataFromInfraWeb(String infrawebUrl) {
        try {
            URL url = new URL(infrawebUrl);

            URLConnection con = url.openConnection();
            InputStream is = con.getInputStream();
            String html = IOUtils.toString(is, "UTF-8");
            parseInfraWebHtml(html);
        } catch (Exception e) {
            Logger.getLogger(Hardware.class).fatal("Erro na leitura dos dados do InfraWeb.");
            e.printStackTrace();
            return false;
        }
        return true;
    }

    private void parseInfraWebHtml(String html) {
        Pattern p;
        Matcher m;

        // Dados básicos
        p = Pattern.compile("<b>Ult.Inventário</b></td><td width='750px'><b>(.*?)</b>");
        m = p.matcher(html);
        if (m.find()) this.lastAccess = m.group(1);

        p = Pattern.compile("<b>Ult.Alteração</b></td><td width='750px'><b>(.*?)</b>");
        m = p.matcher(html);
        if (m.find()) this.lastUpdate = m.group(1);

        p = Pattern.compile("Nome Lógico</td><td colspan=2>(.*?)</td>");
        m = p.matcher(html);
        if (m.find()) this.name = m.group(1);

        p = Pattern.compile("Função</td><td colspan=2>(.*?)</td>");
        m = p.matcher(html);
        if (m.find()) this.function = m.group(1);

        p = Pattern.compile("Localização/Imóvel</td><td colspan=2 width='100px'><input type=text maxlength=100 size=60 name=campo002 value='(.*?)'></td>");
        m = p.matcher(html);
        if (m.find()) this.localization = m.group(1);

        p = Pattern.compile("Função</td><td colspan=2>(.*?)</td>");
        m = p.matcher(html);
        if (m.find()) this.localizationComplement = m.group(1);

        p = Pattern.compile("Complemento</td><td colspan=2><input type=text maxlength=100 size=60 name=campo004 value='(.*?)'></td>");
        m = p.matcher(html);
        if (m.find()) this.localizationComplement = m.group(1);

        p = Pattern.compile("<td>Num.Série/BP/Propriedade</td><td colspan=2>(.*?)</td>");
        m = p.matcher(html);
        if (m.find()) this.serialNumber = m.group(1);

        // RegExp complexo tá levando MUITO tempo pra ser resolvido.
        p = Pattern.compile("Status</td><td colspan=2><font size='1' face='Verdana'><Select name='campo006'>.*?<option value='.*?' selected='yes'>(.*?)</option>.*?</select>");
        m = p.matcher(html);
        if (m.find()) this.function = m.group(1); // 2 mesmo, não foi erro de digitação

        p = Pattern.compile("Centro de Custo</td><td colspan=2>(.*?)</td>");
        m = p.matcher(html);
        if (m.find()) this.costCenter = m.group(1);

        p = Pattern.compile("Observações</td><td class=system_tablebody_left colspan=2><textarea cols=65 rows=3 name=campo009>(.*?)</textarea>");
        m = p.matcher(html);
        if (m.find()) this.observations = m.group(1);

        // Dados de hardware
        p = Pattern.compile("Fabricante</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Fabricante" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Modelo</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Modelo" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Num.Série</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Número de Série" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Nome.Sist.Oper</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Sistema Operacional" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Versao Sist.Oper</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Versão do SO" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Versao ServicePack</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Versão do Service Pack" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Bios</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("BIOS" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Tam.Memoria</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Memória" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Tipo Gabinete</TD><TD align=left>(.*?)</TD>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Tipo de Gabinete" + STRING_SEPARATOR + m.group(1));

        p = Pattern.compile("Processador</td><td><table cellSpacing=0 cellPadding=0 width='100%' border=01><tr><b><td width=300px>Modelo</td><td width=100px>Velocidade</td></b></tr><tr style='BACKGROUND-COLOR: #f1f1f1'><td>(.*?)</td><td>(.*?)</td>");
        m = p.matcher(html);
        if (m.find()) this.hardwareData.add("Processador" + STRING_SEPARATOR + m.group(1) + "@" + m.group(2) + "MHz");

        // Parsar os softwares instalados. Definitivamente usar RegExp não foi uma boa idéia
        /*
         * p = Pattern.compile("Fabricante</b></td><td width=100px><b>Versão</b></td></tr>"); m = p.matcher(html);
         */

    }

    public void save() {
        DAO.save(this);
    }

    public static Hardware findById(String id) {
        return DAO.findById(id);
    }
}
